# @Version        : 1.0
# @Update Time    : 2024/11/24 23:23
# @File           : task_service.py
# @IDE            : PyCharm
# @Desc           : 定时任务业务成
import importlib
import json
from types import ModuleType

from advanced_alchemy import service
from funboost import ApsJobAdder
from sqlalchemy import and_, true

from src import models
from src.config import settings
from src.crud.task_repository import TaskRepo
from src.schemas.task_schema import JobExecStrategy
from src.task_manage.task_utils import TaskUtils


class TaskService(service.SQLAlchemyAsyncRepositoryService[models.SysTask, TaskRepo]):
    """
    定时任务业务层
    """

    repository_type = TaskRepo
    count_with_window_function = False

    @staticmethod
    async def save_task(task: models.SysTask):
        trigger_param = {}
        exec_strategy = task.exec_strategy
        if task.exec_strategy == JobExecStrategy.cron:
            second, minute, hour, day, month, day_of_week, year = (
                TaskUtils.parse_cron_expression(task.expression)
            )
            trigger_param.update(
                second=second,
                minute=minute,
                hour=hour,
                day=day,
                month=month,
                day_of_week=day_of_week,
                year=year,
                start_date=task.start_datetime,
                end_date=task.end_datetime,
            )
        elif task.exec_strategy == JobExecStrategy.interval:
            second, minute, hour, day, week = TaskUtils.parse_interval_expression(
                task.expression
            )
            trigger_param.update(
                weeks=week,
                days=day,
                hours=hour,
                minutes=minute,
                seconds=second,
                start_date=task.start_datetime,
                end_date=task.end_datetime,
            )
        elif task.exec_strategy == JobExecStrategy.date:
            trigger_param.update(run_date=task.expression)
        else:
            exec_strategy = None
        # 动态导入函数
        aps = TaskService.get_task_aps(task.job_class, task.job_params, task.group)
        if not task.is_active:
            job = aps.aps_obj.get_job(str(task.id))
            if job:
                aps.aps_obj.remove_job(str(task.id))
        else:
            # 判断是否更定时任务策略类型
            aps.add_push_job(
                trigger=exec_strategy,
                replace_existing=True,
                id=str(task.id),
                name=task.name,
                kwargs=json.loads(task.job_params),
                **trigger_param,
            )

    @staticmethod
    def __import_module(job_class: str, job_params: str) -> ModuleType:
        """
        反射模块

        :param job_class: 任务执行实体类, 示例：test.
        :param job_params: 任务执行实体类参数
        :return: 类实例
        """
        module_pag = (
            settings.task.SCHEDULER_TASK_JOBS
            + "."
            + job_class[0 : job_class.rindex(".")]
        )
        module_func = job_class[job_class.rindex(".") + 1 :]
        try:
            # 动态导入模块
            pag = importlib.import_module(module_pag)
            return getattr(pag, module_func)
        except ModuleNotFoundError:
            raise ValueError(f"未找到该模块：{module_pag}")
        except AttributeError:
            raise ValueError(f"未找到该模块下的方法：{module_func}")
        except TypeError as e:
            raise ValueError(
                f"参数传递错误：{job_params}, 没有参数时需要为: {{}}, 详情：{e}"
            )

    @staticmethod
    def get_task_aps(job_class: str, job_params: str, group: str) -> ApsJobAdder:
        # 动态导入函数
        func = TaskService.__import_module(job_class, job_params)
        aps = ApsJobAdder(booster=func, job_store_kind=group)
        return aps

    async def init_task(self):
        """
        初始化任务
        :return:
        """
        tasks = await super().list(
            and_(
                models.SysTask.is_active == true(),
                models.SysTask.expression != "once",
            )
        )
        for task in tasks:
            await TaskService.save_task(task)
